﻿using DotNetCommon;
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using DotNetCommon.Extensions;
using System.Threading.Tasks;
using DotNetCommon.Data;
using System.Linq;

namespace DBUtil.Builders
{
    /// <summary>
    /// 查询构建器
    /// </summary>
    public class SelectBuilder<T> : SelectBuilderBase where T : class, new()
    {
        internal SelectBuilder(DBAccess db, string alias) : base(db)
        {
            EntityAliases = [new EntityAlias { EntityInfo = db.GetEntityInfoInternal<T>(false), Alias = alias }];
        }
        #region AsTable
        public override SelectBuilder<T> AsTable(Func<string, string> func) => base.AsTable(func) as SelectBuilder<T>;
        public override SelectBuilder<T> AsTableIf(bool condition, Func<string, string> func) => base.AsTableIf(condition, func) as SelectBuilder<T>;
        #endregion

        #region 复写 CommandTimeout
        public override SelectBuilder<T> CommandTimeout(int timeoutSeconds)
            => base.CommandTimeout(timeoutSeconds) as SelectBuilder<T>;
        public override SelectBuilder<T> CommandTimeoutIf(bool condition, int timeoutSeconds)
            => condition ? CommandTimeout(timeoutSeconds) : this;
        #endregion

        #region Alias
        public new SelectBuilder<T> Alias(string alias) => base.Alias(alias) as SelectBuilder<T>;
        #endregion

        #region 过滤
        public SelectBuilder<T> Where(Expression<Func<T, bool>> expression) => base.Where(expression) as SelectBuilder<T>;
        public SelectBuilder<T> WhereIf(bool condition, Expression<Func<T, bool>> expression) => base.WhereIf(condition, expression) as SelectBuilder<T>;
        #endregion

        #region Distinct
        public new SelectBuilder<T> Distinct(bool isDistinct = true) => base.Distinct(isDistinct) as SelectBuilder<T>;
        #endregion

        #region 排序
        public SelectBuilder<T> OrderBy(Expression<Func<T, object>> expression) => base.OrderBy(expression) as SelectBuilder<T>;
        public SelectBuilder<T> OrderByIf(bool condition, Expression<Func<T, object>> expression) => condition ? OrderBy(expression) : this;

        public SelectBuilder<T> OrderByDesc(Expression<Func<T, object>> expression) => base.OrderByDesc(expression) as SelectBuilder<T>;
        public SelectBuilder<T> OrderByDescIf(bool condition, Expression<Func<T, object>> expression) => condition ? OrderByDesc(expression) : this;

        /// <summary>
        /// 排序,如: select.Order("age desc,id")
        /// </summary>
        public new SelectBuilder<T> Order(string orderSeg) => base.Order(orderSeg) as SelectBuilder<T>;
        #endregion

        #region 分组
        public GroupBuilder<T, TGroupKey> GroupBy<TGroupKey>(Expression<Func<T, TGroupKey>> expression)
        {
            return new GroupBuilder<T, TGroupKey>(this, expression);
        }
        #endregion

        #region 分页
        public new SelectBuilder<T> Page(int pageIndex, int pageSize) => base.Page(pageIndex, pageSize) as SelectBuilder<T>;
        public new SelectBuilder<T> Limit(int size) => base.Limit(size) as SelectBuilder<T>;
        public new SelectBuilder<T> Limit(int startIndex, int size) => base.Limit(startIndex, size) as SelectBuilder<T>;
        #endregion

        #region WithSql
        public new SelectBuilder<T> WithSql(string fromSql) => base.WithSql(fromSql) as SelectBuilder<T>;
        #endregion

        #region ToSql
        /// <summary>
        /// 专供 builder 解析使用, 提供外部已有 midValues
        /// </summary>
        internal string ToSqlFirstOrDefaultInternal(LambdaExpression expression, Dictionary<ParameterExpression, object> midValues, IEnumerable<KeyValuePair<ParameterExpression, string>> aliases)
        {
            this.Limit(1);
            return base.ToSql(EnumSelectToSql.ToList, expression, midValues, aliases);
        }
        /// <summary>
        /// 专供 builder 解析使用, 提供外部已有 midValues
        /// </summary>
        internal string ToSqlInternal(EnumSelectToSql enumSelectToSql, LambdaExpression expression, Dictionary<ParameterExpression, object> midValues, IEnumerable<KeyValuePair<ParameterExpression, string>> aliases)
        {
            return base.ToSql(enumSelectToSql, expression, midValues, aliases);
        }

        private List<(string dtoCol, EntityPropertyInfo entPropInfo)> GetDtoEntMap<Dto>()
        {
            var dtoEntityInfo = db.GetEntityInfoInternal<Dto>();
            var entityInfo = db.GetEntityInfoInternal<T>();
            var allProps = entityInfo.EntityPropertyInfos.Where(i => i.IsColumn && !i.IsIgnoreSelect).Select(i => i.PropNamePure).ToList();
            var dtoMap = dtoEntityInfo.EntityPropertyInfos.Where(i => allProps.Contains(i.PropNamePure)).Select(i =>
            {
                var entPropInfo = entityInfo.EntityPropertyInfos.First(j => j.PropNamePure == i.PropNamePure);
                return (i.PropNameSeg, entPropInfo);
            }).ToList();
            return dtoMap;
        }
        
        //ToSqlFirstOrDefault
        public string ToSqlFirstOrDefault() => base.ToSqlFirstOrDefault(null);
        public string ToSqlFirstOrDefault<Dto>(Expression<Func<T, Dto>> expression = null)
        {
            if (expression != null) return base.ToSqlFirstOrDefault(expression);
            var dtoMap = GetDtoEntMap<Dto>();
            return base.ToSqlFirstOrDefaultDto(dtoMap);
        }
        //ToSql
        public string ToSql() => base.ToSqlList(null);
        //ToSqlList
        public string ToSqlList() => base.ToSqlList(null);

        internal string ToSqlSelectClause() => base.ToSqlSelectClause(null);
        internal override SelectBuilder<T> AddExtraSelectSeg(string seg) => base.AddExtraSelectSeg(seg) as SelectBuilder<T>;

        public string ToSqlList<Dto>(Expression<Func<T, Dto>> expression = null)
        {
            if (expression != null) return base.ToSqlList(expression);
            var dtoMap = GetDtoEntMap<Dto>();
            return base.ToSqlListDto(dtoMap);
        }
        //ToSqlPage
        public string ToSqlPage() => base.ToSqlPage(null);
        public string ToSqlPage(int pageIndex, int pageSize) => Page(pageIndex, pageSize).ToSqlPage(null);
        public string ToSqlPage<Dto>(Expression<Func<T, Dto>> expression = null)
        {
            if (expression != null) return base.ToSqlPage(expression);
            var dtoMap = GetDtoEntMap<Dto>();
            return base.ToSqlPageDto(dtoMap);
        }
        public string ToSqlPage<Dto>(int pageIndex, int pageSize)
        {
            this.Page(pageIndex, pageSize);
            var dtoMap = GetDtoEntMap<Dto>();
            return base.ToSqlPageDto(dtoMap);
        }
        public string ToSqlPage<Dto>(Expression<Func<T, Dto>> expression, int pageIndex, int pageSize)
            => Page(pageIndex, pageSize).ToSqlPage(expression);

        public string ToSqlMax<Dto>(Expression<Func<T, Dto>> expression) => base.ToSql(EnumSelectToSql.Max, expression);
        public string ToSqlMin<Dto>(Expression<Func<T, Dto>> expression) => base.ToSql(EnumSelectToSql.Min, expression);
        public string ToSqlAvg<Dto>(Expression<Func<T, Dto>> expression) => base.ToSql(EnumSelectToSql.Avg, expression);
        public string ToSqlSum<Dto>(Expression<Func<T, Dto>> expression) => base.ToSql(EnumSelectToSql.Sum, expression);
        #endregion

        #region 聚合 & 聚合sql
        #region 聚合Sql
        public string MaxSql<TKey>(Expression<Func<T, TKey>> expression) => base.MaxSql<TKey>(expression);
        public string MinSql<TKey>(Expression<Func<T, TKey>> expression) => base.MinSql<TKey>(expression);
        public string SumSql<TKey>(Expression<Func<T, TKey>> expression) => base.SumSql<TKey>(expression);
        public string AvgSql<TKey>(Expression<Func<T, TKey>> expression) => base.AvgSql<TKey>(expression);
        #endregion

        #region 聚合同步
        public TKey Max<TKey>(Expression<Func<T, TKey>> expression) => base.Max<TKey>(expression);
        public TKey Min<TKey>(Expression<Func<T, TKey>> expression) => base.Min<TKey>(expression);
        public TKey Sum<TKey>(Expression<Func<T, TKey>> expression) => base.Sum<TKey>(expression);
        public TKey Avg<TKey>(Expression<Func<T, TKey>> expression) => base.Avg<TKey>(expression);
        #endregion

        #region 聚合异步
        public async Task<TKey> MaxAsync<TKey>(Expression<Func<T, TKey>> expression) => await base.MaxAsync<TKey>(expression);
        public async Task<TKey> MinAsync<TKey>(Expression<Func<T, TKey>> expression) => await base.MinAsync<TKey>(expression);
        public async Task<TKey> SumAsync<TKey>(Expression<Func<T, TKey>> expression) => await base.SumAsync<TKey>(expression);
        public async Task<TKey> AvgAsync<TKey>(Expression<Func<T, TKey>> expression) => await base.AvgAsync<TKey>(expression);
        #endregion
        #endregion

        #region 执行
        #region 同步
        //FirstOrDefault
        //1. entity
        public T FirstOrDefault()
        {
            var sql = this.Limit(1).ToSqlFirstOrDefault();
            var model = db.SelectModel<T>(sql);
            return model;
        }
        //2. dto lambda
        public Dto FirstOrDefault<Dto>(Expression<Func<T, Dto>> expression)
        {
            var sql = ToSqlFirstOrDefault<Dto>(expression);
            var model = db.SelectModel<Dto>(sql);
            return model;
        }
        //3. dto direct
        public Dto FirstOrDefault<Dto>()
        {
            var sql = this.Limit(1).ToSqlFirstOrDefault<Dto>();
            var model = db.SelectModel<Dto>(sql);
            return model;
        }

        //ToList
        //1. entity
        public List<T> ToList()
        {
            var sql = this.ToSqlList();
            var list = db.SelectModelList<T>(sql);
            return list;
        }
        //2. dto lambda
        public List<Dto> ToList<Dto>(Expression<Func<T, Dto>> expression)
        {
            var sql = ToSqlList<Dto>(expression);
            var list = db.SelectModelList<Dto>(sql);
            return list;
        }
        //3. dto direct
        public List<Dto> ToList<Dto>()
        {
            var sql = this.ToSqlList<Dto>();
            var list = db.SelectModelList<Dto>(sql);
            return list;
        }

        //ToPage
        //1. entity
        public Page<T> ToPage()
        {
            var sql = ToSql(EnumSelectToSql.ToPage);
            return SelectPage<T>(db, sql);
        }
        //1. entity-pageparam
        public Page<T> ToPage(int pageIndex, int pageSize)
        {
            var sql = Page(pageIndex, pageSize).ToSql(EnumSelectToSql.ToPage);
            return SelectPage<T>(db, sql);
        }
        //2. dto lambda
        public Page<Dto> ToPage<Dto>(Expression<Func<T, Dto>> expression) => base.ToPage<Dto>(expression);
        //2. dto lambda-pageparam
        public Page<Dto> ToPage<Dto>(Expression<Func<T, Dto>> expression, int pageIndex, int pageSize) => base.ToPage<Dto>(expression, pageIndex, pageSize);
        //3. dto direct
        public Page<Dto> ToPage<Dto>()
        {
            var sql = this.ToSqlPage<Dto>();
            return SelectPage<Dto>(db, sql);
        }
        //3. dto direct-pageparam
        public Page<Dto> ToPage<Dto>(int pageIndex, int pageSize)
        {
            var sql = this.Page(pageIndex, pageSize).ToSqlPage<Dto>();
            return SelectPage<Dto>(db, sql);
        }
        #endregion

        #region 异步
        //FirstOrDefaultAsync
        //1. entity
        public async Task<T> FirstOrDefaultAsync()
        {
            var sql = this.Limit(1).ToSqlFirstOrDefault();
            var model = await db.SelectModelAsync<T>(sql);
            return model;
        }
        //2. dto lambda
        public async Task<Dto> FirstOrDefaultAsync<Dto>(Expression<Func<T, Dto>> expression)
            => await base.FirstOrDefaultAsync<Dto>(expression);
        //3. dto direct
        public async Task<Dto> FirstOrDefaultAsync<Dto>()
        {
            var sql = this.Limit(1).ToSqlFirstOrDefault<Dto>();
            var model = await db.SelectModelAsync<Dto>(sql);
            return model;
        }

        //ToListAsync
        //1. entity
        public async Task<List<T>> ToListAsync()
        {
            var sql = ToSql(EnumSelectToSql.ToList, null);
            var list = await db.SelectModelListAsync<T>(sql);
            return list;
        }
        //2. dto lambda
        public async Task<List<Dto>> ToListAsync<Dto>(Expression<Func<T, Dto>> expression) => await base.ToListAsync<Dto>(expression);
        //3. dto direct
        public async Task<List<Dto>> ToListAsync<Dto>()
        {
            var sql = ToSqlList<Dto>();
            var list = await db.SelectModelListAsync<Dto>(sql);
            return list;
        }

        //ToPageAsync
        //1. entity
        public async Task<Page<T>> ToPageAsync()
        {
            var sql = ToSqlPage();
            return await SelectPageAsync<T>(db, sql);
        }
        //1. entity-pageparam
        public async Task<Page<T>> ToPageAsync(int pageIndex, int pageSize) => await this.Page(pageIndex, pageSize).ToPageAsync<T>();
        //2. dto lambda
        public async Task<Page<Dto>> ToPageAsync<Dto>(Expression<Func<T, Dto>> expression) => await base.ToPageAsync<Dto>(expression);
        //2. dto lambda-param
        public async Task<Page<Dto>> ToPageAsync<Dto>(Expression<Func<T, Dto>> expression, int pageIndex, int pageSize) => await base.ToPageAsync<Dto>(expression, pageIndex, pageSize);
        //3. dto direct
        public async Task<Page<Dto>> ToPageAsync<Dto>()
        {
            var sql = ToSqlPage<Dto>();
            return await SelectPageAsync<Dto>(db, sql);
        }
        //3. dto direct-param
        public async Task<Page<Dto>> ToPageAsync<Dto>(int pageIndex, int pageSize)
        {
            var sql = this.Page(pageIndex, pageSize).ToSqlPage<Dto>();
            return await SelectPageAsync<Dto>(db, sql);
        }
        #endregion
        #endregion

        #region WhereSeg
        public override SelectBuilder<T> WhereSeg<TAny>(Expression<Func<TAny, bool>> filter)
            => base.WhereSeg(filter) as SelectBuilder<T>;
        public override SelectBuilder<T> WhereSegIf<TAny>(bool condition, Expression<Func<TAny, bool>> filter)
            => base.WhereSegIf(condition, filter) as SelectBuilder<T>;
        public override SelectBuilder<T> WhereSeg<TAny, TAny2>(Expression<Func<TAny, TAny2, bool>> filter)
            => base.WhereSeg(filter) as SelectBuilder<T>;
        public override SelectBuilder<T> WhereSegIf<TAny, TAny2>(bool condition, Expression<Func<TAny, TAny2, bool>> filter)
            => base.WhereSegIf(condition, filter) as SelectBuilder<T>;
        public override SelectBuilder<T> WhereSeg<TAny, TAny2, TAny3>(Expression<Func<TAny, TAny2, TAny3, bool>> filter)
             => base.WhereSeg(filter) as SelectBuilder<T>;
        public override SelectBuilder<T> WhereSegIf<TAny, TAny2, TAny3>(bool condition, Expression<Func<TAny, TAny2, TAny3, bool>> filter)
            => base.WhereSegIf(condition, filter) as SelectBuilder<T>;
        public override SelectBuilder<T> WhereSeg<TAny, TAny2, TAny3, TAny4>(Expression<Func<TAny, TAny2, TAny3, TAny4, bool>> filter)
            => base.WhereSeg(filter) as SelectBuilder<T>;
        public override SelectBuilder<T> WhereSegIf<TAny, TAny2, TAny3, TAny4>(bool condition, Expression<Func<TAny, TAny2, TAny3, TAny4, bool>> filter)
             => base.WhereSegIf(condition, filter) as SelectBuilder<T>;
        #endregion
        #region Where
        public override SelectBuilder<T> Where(string filter) => base.Where(filter) as SelectBuilder<T>;
        public override SelectBuilder<T> WhereIf(bool condition, string filter) => base.WhereIf(condition, filter) as SelectBuilder<T>;
        #endregion

        #region Join
        public SelectBuilder<T, T2> LeftJoin<T2>(Expression<Func<T, T2, bool>> joinExp) where T2 : class, new()
        {
            return new SelectBuilder<T, T2>(this, (joinExp, EnumJoinType.LeftJoin), "t2");
        }
        public SelectBuilder<T, T2> LeftJoin<T2>(Expression<Func<T, T2, bool>> joinExp, string alias) where T2 : class, new()
        {
            if (alias.IsNullOrEmptyOrWhiteSpace()) alias = "t2";
            return new SelectBuilder<T, T2>(this, (joinExp, EnumJoinType.LeftJoin), alias);
        }
        public SelectBuilder<T, T2> RightJoin<T2>(Expression<Func<T, T2, bool>> joinExp) where T2 : class, new()
        {
            return new SelectBuilder<T, T2>(this, (joinExp, EnumJoinType.RightJoin), "t2");
        }
        public SelectBuilder<T, T2> RightJoin<T2>(Expression<Func<T, T2, bool>> joinExp, string alias) where T2 : class, new()
        {
            if (alias.IsNullOrEmptyOrWhiteSpace()) alias = "t2";
            return new SelectBuilder<T, T2>(this, (joinExp, EnumJoinType.RightJoin), alias);
        }
        public SelectBuilder<T, T2> InnerJoin<T2>(Expression<Func<T, T2, bool>> joinExp) where T2 : class, new()
        {
            return new SelectBuilder<T, T2>(this, (joinExp, EnumJoinType.InnerJoin), "t2");
        }
        public SelectBuilder<T, T2> InnerJoin<T2>(Expression<Func<T, T2, bool>> joinExp, string alias) where T2 : class, new()
        {
            if (alias.IsNullOrEmptyOrWhiteSpace()) alias = "t2";
            return new SelectBuilder<T, T2>(this, (joinExp, EnumJoinType.InnerJoin), alias);
        }
        public SelectBuilder<T, T2> CrossJoin<T2>(Expression<Func<T, T2, bool>> joinExp) where T2 : class, new()
        {
            return new SelectBuilder<T, T2>(this, (joinExp, EnumJoinType.CrossJoin), "t2");
        }
        public SelectBuilder<T, T2> CrossJoin<T2>(Expression<Func<T, T2, bool>> joinExp, string alias) where T2 : class, new()
        {
            if (alias.IsNullOrEmptyOrWhiteSpace()) alias = "t2";
            return new SelectBuilder<T, T2>(this, (joinExp, EnumJoinType.CrossJoin), alias);
        }
        #endregion

        #region 转到insert
        public InsertFromSelectBuilder<TInsert> AsInsert<TInsert>(Expression<Func<T, TInsert>> expression) where TInsert : class, new()
        {
            var names = ExpressionHelper.GetInitOrReturnPropNames(expression).ToArray();
            if (names.IsNullOrEmpty()) throw new Exception($"不能在 AsInsert 方法中使用 \"i=>i\" 这种形式的表达式!");
            return new InsertFromSelectBuilder<TInsert>(db, this, expression, names);
        }
        #endregion
    }

    /// <summary>
    /// 分组查询构建器
    /// </summary>
    public class GroupBuilder<T, TGroupKey> : GroupBuilderBase where T : class, new()
    {
        internal GroupBuilder(SelectBuilder<T> selectBuilder, Expression<Func<T, TGroupKey>> groupExpression) : base(selectBuilder, groupExpression) { }

        #region 过滤
        public GroupBuilder<T, TGroupKey> Having(Expression<Func<IGroupFilter<T, TGroupKey>, bool>> expression)
        {
            Ensure.NotNull(expression, nameof(expression));
            havings.Add(expression);
            return this;
        }
        public GroupBuilder<T, TGroupKey> HavingIf(bool condition, Expression<Func<IGroupFilter<T, TGroupKey>, bool>> expression)
            => condition ? Having(expression) : this;

        public GroupBuilder<T, TGroupKey> HavingRaw(string filter)
        {
            Ensure.NotNull(filter, nameof(filter));
            havings.Add(filter);
            return this;
        }
        public GroupBuilder<T, TGroupKey> HavingRawIf(bool condition, string filter)
            => condition ? HavingRaw(filter) : this;
        #endregion

        #region 分页
        public override GroupBuilder<T, TGroupKey> Page(int pageIndex, int pageSize)
            => base.Page(pageIndex, pageSize) as GroupBuilder<T, TGroupKey>;
        public override GroupBuilder<T, TGroupKey> Limit(int size)
            => base.Limit(size) as GroupBuilder<T, TGroupKey>;
        public override GroupBuilder<T, TGroupKey> Limit(int startIndex, int size)
            => base.Limit(size, startIndex) as GroupBuilder<T, TGroupKey>;
        #endregion

        #region ToSql
        public string ToSqlFirstOrDefault<Dto>(Expression<Func<IGroupFilter<T, TGroupKey>, Dto>> expression)
            => base.ToSqlFirstOrDefault(expression);
        public string ToSqlList<Dto>(Expression<Func<IGroupFilter<T, TGroupKey>, Dto>> expression)
            => base.ToSqlList(expression);
        public string ToSqlPage<Dto>(Expression<Func<IGroupFilter<T, TGroupKey>, Dto>> expression)
            => base.ToSqlPage(expression);
        public string ToSqlPage<Dto>(Expression<Func<IGroupFilter<T, TGroupKey>, Dto>> expression, int pageIndex, int pageSize)
            => base.ToSqlPage(expression, pageIndex, pageSize);
        #endregion

        #region 排序
        public GroupBuilder<T, TGroupKey> OrderBy(Expression<Func<IGroupFilter<T, TGroupKey>, object>> expression)
            => base.OrderBy(expression) as GroupBuilder<T, TGroupKey>;

        public GroupBuilder<T, TGroupKey> OrderByDesc(Expression<Func<IGroupFilter<T, TGroupKey>, object>> expression)
            => base.OrderByDesc(expression) as GroupBuilder<T, TGroupKey>;

        /// <summary>
        /// 排序,如: select.Order("age desc,id")
        /// </summary>
        public override GroupBuilder<T, TGroupKey> Order(string orderSeg)
            => base.Order(orderSeg) as GroupBuilder<T, TGroupKey>;
        #endregion

        #region 执行
        #region 同步
        public Dto FirstOrDefault<Dto>(Expression<Func<IGroupFilter<T, TGroupKey>, Dto>> expression)
            => base.FirstOrDefault<Dto>(expression);
        public List<Dto> ToList<Dto>(Expression<Func<IGroupFilter<T, TGroupKey>, Dto>> expression)
            => base.ToList<Dto>(expression);
        public Page<Dto> ToPage<Dto>(Expression<Func<IGroupFilter<T, TGroupKey>, Dto>> expression)
            => base.ToPage<Dto>(expression);
        public Page<Dto> ToPage<Dto>(Expression<Func<IGroupFilter<T, TGroupKey>, Dto>> expression, int pageIndex, int pageSize)
            => base.ToPage<Dto>(expression, pageIndex, pageSize);
        #endregion
        #region 异步
        public async Task<Dto> FirstOrDefaultAsnc<Dto>(Expression<Func<IGroupFilter<T, TGroupKey>, Dto>> expression)
            => await base.FirstOrDefaultAsnc<Dto>(expression);
        public async Task<List<Dto>> ToListAsync<Dto>(Expression<Func<IGroupFilter<T, TGroupKey>, Dto>> expression)
            => await base.ToListAsync<Dto>(expression);
        public async Task<Page<Dto>> ToPageAsync<Dto>(Expression<Func<IGroupFilter<T, TGroupKey>, Dto>> expression)
            => await base.ToPageAsync<Dto>(expression);
        public async Task<Page<Dto>> ToPageAsync<Dto>(Expression<Func<IGroupFilter<T, TGroupKey>, Dto>> expression, int pageIndex, int pageSize)
            => await base.ToPageAsync<Dto>(expression, pageIndex, pageSize);
        #endregion
        #endregion
    }

    public interface IGroupFilter<T, TGroupKey> where T : class, new()
    {
        public TGroupKey Key { get; }
        public int Length { get; }

        #region 聚合函数 sum max min avg
        //https://dev.mysql.com/doc/refman/8.0/en/aggregate-functions.html
        public TKey Max<TKey>(Func<T, TKey> expression);
        public TKey Min<TKey>(Func<T, TKey> expression);
        public TKey Sum<TKey>(Func<T, TKey> expression);
        public TKey Avg<TKey>(Func<T, TKey> expression);
        #endregion

        #region 字符串 Join
        /// <summary>
        /// string_agg(sqlserver/postgresql) group_concat(mysql)
        /// <list type="bullet">
        /// <item>mysql: <seealso href="https://dev.mysql.com/doc/refman/8.0/en/aggregate-functions.html#function_group-concat"/></item>
        /// <item>sqlserver: <seealso href="https://learn.microsoft.com/zh-cn/sql/t-sql/functions/string-agg-transact-sql?view=sql-server-ver15"/></item>
        /// </list>
        /// </summary>
        /// <remarks>注意: 仅mysql支持 distinct</remarks>
        public string Join(Func<T, string> expression, string separator, Func<T, object> orderBy, bool desc, bool isDistinct);
        /// <summary>
        /// string_agg(sqlserver/postgresql) group_concat(mysql)
        /// <list type="bullet">
        /// <item>mysql: <seealso href="https://dev.mysql.com/doc/refman/8.0/en/aggregate-functions.html#function_group-concat"/></item>
        /// <item>sqlserver: <seealso href="https://learn.microsoft.com/zh-cn/sql/t-sql/functions/string-agg-transact-sql?view=sql-server-ver15"/></item>
        /// </list>
        /// </summary>
        public string Join(Func<T, string> expression, string separator, Func<T, object> orderBy, bool desc);
        /// <summary>
        /// string_agg(sqlserver/postgresql) group_concat(mysql)
        /// <list type="bullet">
        /// <item>mysql: <seealso href="https://dev.mysql.com/doc/refman/8.0/en/aggregate-functions.html#function_group-concat"/></item>
        /// <item>sqlserver: <seealso href="https://learn.microsoft.com/zh-cn/sql/t-sql/functions/string-agg-transact-sql?view=sql-server-ver15"/></item>
        /// </list>
        /// </summary>
        public string Join(Func<T, string> expression, string separator);
        #endregion
    }
}
